import * as go from 'gojs';
import { produce } from 'immer'; // 一个immutable库
import * as React from 'react';
import { DiagramWrapper } from '../FlowComponent/DiagramWrapper';
import { PaletteWrapper } from '../FlowComponent/PaletteWrapper';
import { debounce } from 'lodash';

import { getIntentionsAll, postFlow } from '../../servers/servers';
import './style.scss';
import { Row, Col, Drawer, Radio, Spin, message } from 'antd';
import { getFlow } from 'admin/servers/servers';

import { RadioChangeEvent } from 'antd/lib/radio';
import { DiagramWrapperView } from '../FlowComponent/DiagramWrapperView';
import SelectionInspector from '../FlowComponent/SelectionInspector';

interface ContextProps {
  versionId: number;
  isView: boolean;
  category: string;
  selectedData: any;
  nodeDataArray: any;
  onInputChange: (id: string, value: any, isBlur: boolean) => void;
  onRemoveLink: (path: string, value: string, nodeKey?: number) => void;
  onModifyLink: (path: string, oldValue: string, value: string, nodeKey: number) => void;
}

/**共享变量:创建一个Context,*/
export const InspectorContext = React.createContext({} as ContextProps);

/**
 * 流程组件State
 *
 * Use a linkDataArray since we'll be using a GraphLinksModel,
 * and modelData for demonstration purposes. Note, though, that
 * both are optional props in ReactDiagram.
 */
interface IState {
  paletteNodeDataArray: Array<go.ObjectData>;
  nodeDataArray: Array<go.ObjectData>;
  linkDataArray: Array<go.ObjectData>;
  modelData: go.ObjectData;
  selectedData: go.ObjectData | null;
  skipsDiagramUpdate: boolean;
  isFullbollen_left: any;
  visible: boolean;
  diagramId: number;
  /**默认true只读-已发布、false可编辑-草稿*/
  isView: boolean;
  /**流程图加载中 */
  loading: boolean;
}

/**
 * 流程调度管理页
 * 组合了流程节点主渲染视图，右侧组件配置项，下侧调试JSON项
 * 示例：AI管理-机器人管理-版本管理-配置话术流程
 * 常见事件以及回调索引如下：
 * 1. 点击主视图内单项，触发右侧检查器的切换：handleDiagramEvent
 * 2. 拖拽上方控件至主视图/删除主视图组件/更新组件属性值：handleModelChange
 * 3. 将两个组件 连线/删除连线/切换连线组件： handleModelChange
 */
class FlowManage extends React.PureComponent<{ versionId: number }, IState> {
  // Maps to store key -> arr index for quick lookups
  private mapNodeKeyIdx: Map<go.Key, number>;
  private mapLinkKeyIdx: Map<go.Key, number>;
  private container: React.RefObject<any>;
  constructor(props: { versionId: number }) {
    super(props);
    this.container = React.createRef();
    this.state = {
      loading: false,
      isView: true,
      diagramId: 0,
      visible: false,
      isFullbollen_left: 24,
      // 调色板的组件数据
      paletteNodeDataArray: [
        {
          key: 1,
          icon: 'attention',
          category: 'IntentComponent',
          /**意图组件名称*/
          title: '意图组件',
          /**话术内容*/
          script: '',
          /**跳回话术*/
          jumpBackScript: '',
          /**短信设置 on/off */
          smsSwitch: 'off',
          /**短信模板 */
          smsTemplateId: undefined,
          /**打断设置 on/off */
          breakSwitch: 'off',
          /**打断规则 */
          ruleBreak: undefined,
          /**按键标记（底部按钮过滤条件） */
          keyFlag: 'Intention',
          /**意图列表 */
          intentionArray: [
            { intentionId: -1, text: '肯定', interfaceInfo: null },
            { intentionId: -2, text: '否定', interfaceInfo: null },
          ],
          fillcolor: '#3BC44E',
          // [
          //   {
          //     text: "同意",
          //     intentionId: 111,
          //     interfaceInfo: {
          //       name: "userService",
          //       interfaceId: "接口Id",
          //       method: "post",
          //       url: "http://www.xxxx.xxx/",
          //       requestParam: [
          //         {
          //           key: "name",
          //           value: "hello",
          //         },
          //         {
          //           key: "age",
          //           value: "80",
          //         },
          //         {
          //           key: "location",
          //           value: "xxx",
          //         },
          //       ],
          //       responseParam: {
          //         key: "respA",
          //         value: "$respA",
          //       },
          //     },
          //   },
          //   {
          //     text: "不同意",
          //     intentionId: 222,
          //     interfaceInfo: null,
          //   },
          //   {
          //     text: "未理解",
          //     intentionId: 333,
          //     interfaceInfo: null,
          //   },
          // ],

          /**使用全局未理解 on/off，为兼容老的流程，默认无此项配置参数，自定义配置时非'on' */
          useGlobalNotUnderstoodSwitch: 'on',
          /**未理解-话术 ["话术1","话术2"]*/
          notUnderstoodScriptArray: [],
          /**未理解-跳转节点 */
          notUnderstoodFollowUpAct: undefined,
          // notUnderstoodFollowUpAct: {
          //   /**组件的key */
          //   value: null,
          //   /**组件名 */
          //   label: null,
          //   /**猜: 应该是索引值 */
          //   key: null,
          // },

          /**使用全局超时静默 on/off，为兼容老的流程，默认无此项配置参数，自定义配置时非'on'*/
          useGlobalTimeoutSwitch: 'on',
          /**超时话术数组，可新增，数组长度不超过3*/
          timeoutScriptArray: [
            // {
            //   /**超时时长 单位s */
            //   timeout: 5,
            //   /**超时话术 */
            //   script: undefined,
            // },
          ],
          /**最后一次超时时长 单位s */
          timeoutFollowUpStateVal: 5,
          /**最后超时跳转节点 */
          timeoutFollowUpAct: undefined,
          // timeoutFollowUpAct: {
          //   /**组件的key */
          //   value: null,
          //   /**组件名 */
          //   label: null,
          //   /**猜: 应该是索引值 */
          //   key: null,
          // },
          //按键数据
        },
        {
          key: 2,
          icon: 'presskey',
          category: 'KeyComponent',
          // 按键组件名称
          title: '按键组件',
          // 话术内容
          script: '',
          // script: "你好，数字1，2，3分别代表满意，一般和不满意，请输入",
          // 短信设置 on/off
          smsSwitch: 'off',
          /**短信模板id */
          smsTemplateId: undefined,
          //按键标记（底部按钮过滤条件） PressKey/ReceiveNumber 按键/收号
          keyFlag: 'PressKey',
          //按键数据
          pressKeyArray: [
            { key: '未识别' },
            // { key: "2" },
            // { key: "3" },
            // { key: "4" },
            // { key: "*" },
          ],
          //收号状态下，默认的语义配置
          receiveNumberDefaultArray: [{ intent: '收集到按键值' }, { intent: '未收集到按键值' }],
          //收号最小位数
          receiveNumberMin: '',
          //收号最大位数
          receiveNumberMax: '',
          //收号是否#号结束
          receiveNumberEnd: true,
          //重复次数 1/2
          numberOfAttempts: 1,
          timeout: undefined,
          fillcolor: '#BAC2CE',
        },
        {
          key: 3,
          icon: 'condition',
          category: 'ConditionComponent',
          title: '条件组件',
          fillcolor: '#5092F7',
          conditionArray: [
            // {
            //   describe: "年轻教师",
            //   expressions: [
            //     {
            //       leftVal: "${age}",
            //       condition: "≤",
            //       rightVal: "30",
            //     },
            //     {
            //       leftVal: "${职业}",
            //       condition: "=",
            //       rightVal: "老师",
            //     },
            //   ],
            // },
            // {
            //   describe: "老教师",
            //   expressions: [
            //     {
            //       leftVal: "${age}",
            //       condition: ">",
            //       rightVal: "30",
            //     },
            //     {
            //       leftVal: "${职业}",
            //       condition: "=",
            //       rightVal: "老师",
            //     },
            //   ],
            // },
          ],
        },
        {
          key: 4,
          icon: 'interface',
          category: 'InterfaceComponent',
          //接口组件名称
          title: '接口组件',
          fillcolor: '#5092F7',
          interfaceInfo: {
            /**接口id */
            interfaceId: '',
            /**接口名称 */
            name: '',
            method: '',
            /**接口地址 */
            url: '',
            requestParam: [
              // { key: "name", value: "张三" },
              // { key: "age", value: "80" },
              // { key: "location", value: "xxx" },
            ],
            // requestParam: [],
            responseParam: [
              // { key: "name", value: "张三" },
              // { key: "age", value: "80" },
              // { key: "location", value: "xxx" },
            ],
          },
        },
        // {
        //   key: 5,
        //   icon: 'person',
        //   category: 'TransferManualServiceComponent',
        //   // 转人工组件名称
        //   title: '转人工组件',
        //   fillcolor: '#5092F7',
        //   // 转人工方式, 0:转人机协同坐席; 1:转指定号码
        //   transferManualMode: 0,
        //   // 转人工号码，注意：如果能用undefined，不显示编辑组件提示
        //   phoneNumber: '',
        //   // phoneNumber: "13111111111",
        //   // 按键标记（底部按钮过滤条件）
        //   keyFlag: 'TransferManualIntention',
        //   // 按键数据
        //   transferManualIntentionArray: [{ intent: '转人工完成' }, { intent: '转人工失败' }],
        //   // 等待音设置 on/off
        //   waitVoiceSwitch: 'off',
        //   // 等待提示类型 0-TTS,1-录音
        //   voiceType: undefined,
        //   //【TTS类型】配置TTS
        //   flowTTSWaitTipsInfo: {
        //     // 提示内容
        //     // text: undefined,
        //     // // 音色：TTS id
        //     // ttsId: undefined,
        //     // // 音量
        //     // volume: 1,
        //     // // 语速
        //     // speechSpeed: 1,
        //     // // 语调
        //     // intonation: 1,
        //   },
        //   // 提示音-文件名
        //   tipsVoiceFile: undefined,
        //   // 提示音-上传后的远程文件
        //   tipsVoiceFileRemote: undefined,
        //   // 等待音乐-文件名
        //   waitVoiceFile: undefined,
        //   // 等待音乐-上传后的远程文件
        //   waitVoiceFileRemote: undefined,
        //   // 播放时长 单位: 秒
        //   playDuration: undefined,
        // },
        {
          key: 6,
          icon: 'skip',
          category: 'SkipComponent',
          title: '跳转组件',
          script: '',
          timeout: 5,
          fillcolor: '#5092F7',
        },
        // {   //应项目需求暂时注释掉
        //   key: 6,
        //   icon: "collect",
        //   category: "InfoCollectionComponent",
        //   //信息收集组件名称
        //   title: "信息收集组件",
        //   fillcolor: '#5092F7',
        //   //话术内容
        //   //script: "请问您的身份证号是多少？",
        //   script: "",
        //   //变量名
        //   variableName: "",
        //   //意图列表:后端支持多个, 前端只需传一个
        //   intention: [
        //     // {
        //     //   text: null,
        //     //   /**意图ID */
        //     //   intentionId: "",
        //     // },
        //   ],
        //   //重复次数
        //   numberOfAttempts: 1,
        //   //超时话术数组，可新增，数组长度不超过3
        //   timeoutScriptArray: [
        //     // {
        //     //   /**超时时长 单位s */
        //     //   timeout: 5,
        //     //   /**超时话术 */
        //     //   script: undefined,
        //     // },
        //   ],
        //   //最后一次超时时长 单位s
        //   timeoutFollowUpStateVal: 5,
        //   /**最后超时跳转节点 */
        //   timeoutFollowUpAct: undefined,
        //   // timeoutFollowUpAct: {
        //   //   组件的key
        //   //   value: "",
        //   //   组件名
        //   //   label: "",
        //   //   猜: 应该是索引值
        //   //   key: "",
        //   // },
        //   //转人工-输号码
        //   phoneNumber: "",
        // },
        {
          key: 7,
          icon: 'end',
          category: 'EndComponent',
          title: '结束语组件',
          fillcolor: '#F75050',
          script: '',
          smsSwitch: 'off', // 设置短信
          //短信模板id
          smsTemplateId: undefined,
        },
      ],
      nodeDataArray: [],
      linkDataArray: [],
      modelData: {
        canRelink: false,
      },
      selectedData: null,
      skipsDiagramUpdate: false,
    };
    // init maps
    this.mapNodeKeyIdx = new Map<go.Key, number>();
    this.mapLinkKeyIdx = new Map<go.Key, number>();

    // bind handler methods
    this.handleDiagramEvent = this.handleDiagramEvent.bind(this);
    this.dbhandleDiagramEvent = this.dbhandleDiagramEvent.bind(this);
    this.onehandleDiagramEvent = this.onehandleDiagramEvent.bind(this);
    this.handleModelChange = this.handleModelChange.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleStatusChange = this.handleStatusChange.bind(this);
    this.handleNodeChange = this.handleNodeChange.bind(this);
    this.handleRelinkChange = this.handleRelinkChange.bind(this);
    this.handleRemoveLink = this.handleRemoveLink.bind(this);
    this.handleModifyLink = this.handleModifyLink.bind(this);
  }
  /**加载图表数据 */
  componentDidMount() {
    // console.log('FlowManage=====componentDidMount');
    this.createFlowModel('publish');
    this.initIntentions();
  }

  // 不能在组件销毁后设置state，防止出现内存泄漏的情况
  componentWillUnmount = () => {
    this.setState = () => {
      return;
    };
  };

  // 初始化意图列表-添加默认肯定和否定意图
  initIntentions = async () => {
    try {
      const { data = [] } = await getIntentionsAll({
        pageNo: 1,
        pageSize: 6,
        versionId: this.props.versionId,
        intentionName: '',
      });
      data.forEach((index: any) => {
        const tempid = index.intentionId;
        const arr = JSON.parse(JSON.stringify(this.state.paletteNodeDataArray));
        if (index.intentionName === '肯定') {
          arr[0].intentionArray[0].intentionId = tempid;
          this.setState({
            paletteNodeDataArray: arr,
          });
          // console.log(this.state.paletteNodeDataArray);
        } else if (index.intentionName === '否定') {
          arr[0].intentionArray[1].intentionId = tempid;
          this.setState({
            paletteNodeDataArray: arr,
          });
          // console.log(this.state.paletteNodeDataArray);
        }
      });
    } catch (error) {
      console.error(`系统异常: ${JSON.stringify(error)}`);
    }
  };

  // 初始流程图
  initFlowMaps = (nodeDataArray: any, linkDataArray: any) => {
    // console.log('initFlowMaps', nodeDataArray, linkDataArray);
    this.refreshNodeIndex(nodeDataArray);
    this.refreshLinkIndex(linkDataArray);
  };
  /**
   * Update map of node keys to their index in the array.
   */
  private refreshNodeIndex(nodeArr: Array<go.ObjectData>) {
    this.mapNodeKeyIdx.clear();
    nodeArr.forEach((n: go.ObjectData, idx: number) => {
      this.mapNodeKeyIdx.set(n.key, idx);
    });
  }

  /**
   * Update map of link keys to their index in the array.
   */
  private refreshLinkIndex(linkArr: Array<go.ObjectData>) {
    this.mapLinkKeyIdx.clear();
    linkArr.forEach((l: go.ObjectData, idx: number) => {
      this.mapLinkKeyIdx.set(l.key, idx);
    });
  }
  // 监控单击事件
  public onehandleDiagramEvent(e: go.DiagramEvent) {
    const name = e.name;
    if (this.state.visible) {
      // 判断单击事件是在弹出窗展开的情况下还是未展开
      // 配置展开，则切换弹窗数据
      switch (name) {
        case 'ObjectSingleClicked': {
          const sel = e.subject.part.kb;
          if (sel) {
            const idx = this.mapNodeKeyIdx.get(sel.key);
            if (idx !== undefined && idx >= 0) {
              console.log(sel, '节点-单击-切换配置--1');
              this.setState(
                produce((draft: IState) => {
                  const nd = draft.nodeDataArray[idx];
                  draft.selectedData = nd;
                })
              );
            }
          }
          break;
        }
        default:
          break;
      }
    }
  }
  // 监控流程图双击事件
  public dbhandleDiagramEvent(e: go.DiagramEvent) {
    const name = e.name;
    if (this.state.visible) {
      this.onClose();
    } else {
      switch (name) {
        case 'ObjectDoubleClicked': {
          const sel = e.subject.part.kb;
          if (sel) {
            const idx = this.mapNodeKeyIdx.get(sel.key);
            if (idx !== undefined && idx > 0) {
              // Note：除【开始组件】外-展开配置弹窗
              console.log(sel, '【组件】-双击-展开配置');
              this.showDrawer();
              this.setState(
                produce((draft: IState) => {
                  const nd = draft.nodeDataArray[idx];
                  draft.selectedData = nd;
                })
              );
            }
          }
          break;
        }
        default:
          break;
      }
    }
  }
  /**
   * Handle any relevant DiagramEvents, in this case just selection changes.
   * On ChangedSelection, find the corresponding data and set the selectedData state.
   * 处理所有相关的DiagramEvents，在本例中仅更改选择。
   * 在ChangedSelection上，找到相应的数据并设置selectedData状态。
   * @param e a GoJS DiagramEvent
   */
  public handleDiagramEvent(e: go.DiagramEvent) {
    console.log('流程图-区域内-普通点击事件-0');
    if (this.state.visible) {
      this.onClose();
    }
  }

  /**
   * Handle GoJS model changes, which output an object of data changes via Model.toIncrementalData.
   * This method iterates over those changes and updates state to keep in sync with the GoJS model.
   * @param obj a JSON-formatted string
   * 当拖拽组件进入图表时, 触发change事件, 将新的数据setState到数据模型中
   */
  public handleModelChange(obj: go.IncrementalData) {
    // console.log('handleModelChange*****obj:', obj);
    // 有改动的数据
    const insertedNodeKeys = obj.insertedNodeKeys; // 新增组件的key
    const modifiedNodeData = obj.modifiedNodeData; // 更新的节点数据
    const removedNodeKeys = obj.removedNodeKeys; // 删除节点的key
    const insertedLinkKeys = obj.insertedLinkKeys; // 插入连接关系数据的key
    const modifiedLinkData = obj.modifiedLinkData; // 更新连接关系数据
    const removedLinkKeys = obj.removedLinkKeys; // 删除连接关系数据的key
    const modifiedModelData = obj.modelData; // 更新后数据模型

    // maintain maps of modified data so insertions don't need slow lookups
    // 维护已修改数据的映射，这样插入就不需要慢速查找
    const modifiedNodeMap = new Map<go.Key, go.ObjectData>();
    const modifiedLinkMap = new Map<go.Key, go.ObjectData>();
    this.setState(
      produce((draft: IState) => {
        // 1-节点数据
        let narr = draft.nodeDataArray;
        // 有更新节点
        if (modifiedNodeData) {
          modifiedNodeData.forEach((nd: go.ObjectData) => {
            modifiedNodeMap.set(nd.key, nd);
            const idx = this.mapNodeKeyIdx.get(nd.key);
            if (idx !== undefined && idx >= 0) {
              narr[idx] = nd;
              if (draft.selectedData && draft.selectedData.key === nd.key) {
                draft.selectedData = nd;
              }
            }
          });
        }
        // 有插入节点
        if (insertedNodeKeys) {
          insertedNodeKeys.forEach((key: go.Key) => {
            const nd = modifiedNodeMap.get(key);
            const idx = this.mapNodeKeyIdx.get(key);
            if (nd && idx === undefined) {
              // nodes won't be added if they already exist
              this.mapNodeKeyIdx.set(nd.key, narr.length);
              narr.push(nd);
            }
          });
        }
        // 有删除节点
        if (removedNodeKeys) {
          narr = narr.filter((nd: go.ObjectData) => {
            if (removedNodeKeys.includes(nd.key)) {
              return false;
            }
            return true;
          });
          draft.nodeDataArray = narr;
          this.refreshNodeIndex(narr);
        }
        // 2-连线数据
        let larr = draft.linkDataArray;
        // 连接关系有变化
        if (modifiedLinkData) {
          modifiedLinkData.forEach((ld: go.ObjectData) => {
            modifiedLinkMap.set(ld.key, ld);
            const idx = this.mapLinkKeyIdx.get(ld.key);
            if (idx !== undefined && idx >= 0) {
              larr[idx] = ld;
              if (draft.selectedData && draft.selectedData.key === ld.key) {
                draft.selectedData = ld;
              }
            }
          });
        }
        // 新增连接
        if (insertedLinkKeys) {
          insertedLinkKeys.forEach((key: go.Key) => {
            const ld = modifiedLinkMap.get(key);
            const idx = this.mapLinkKeyIdx.get(key);
            if (ld && idx === undefined) {
              // links won't be added if they already exist
              this.mapLinkKeyIdx.set(ld.key, larr.length);
              larr.push(ld);
            }
          });
        }
        // 删除连接
        if (removedLinkKeys) {
          larr = larr.filter((ld: go.ObjectData) => {
            if (removedLinkKeys.includes(ld.key)) {
              return false;
            }
            return true;
          });
          draft.linkDataArray = larr;
          this.refreshLinkIndex(larr);
        }
        // handle model data changes, for now just replacing with the supplied object
        if (modifiedModelData) {
          draft.modelData = modifiedModelData;
        }
        draft.skipsDiagramUpdate = true; // the GoJS model already knows about
      })
    );
  }

  /**
   * 修改某个连线
   * @param path 待修改连线的属性路径
   * @param oldValue 原来的属性值
   * @param value 新的属性值
   * @param fromKey 待修改连线对应的起始节点，同时也是当前组件节点key值
   */
  public handleModifyLink(path: string, oldValue: string, value: string, fromKey: number) {
    console.log('修改条件组件-', path, oldValue, value, fromKey);
    this.setState(
      produce((draft: IState) => {
        const larr = draft.linkDataArray;

        larr.forEach((ld: go.ObjectData, index: number) => {
          if (fromKey && ld.from === fromKey && ld[path] === oldValue) {
            larr[index][path] = value;
          }
        });
        draft.linkDataArray = larr;
        this.refreshLinkIndex(larr);
        draft.skipsDiagramUpdate = false;
      })
    );
  }

  /**
   * 删除某个连线
   * @param path 待删除连线的属性路径
   * @param value 待删除连线的特定属性的属性值
   * @param fromKey 待删除连线对应的起始节点，同时也是当前组件节点key值
   * @特殊情况 当path为"from"时，fromKey===value，此时参数可省略fromKey
   * @删除连线条件 只删除起点为当前节点的连线
   */
  public handleRemoveLink(path: string, value: string, fromKey?: number) {
    this.setState(
      produce((draft: IState) => {
        let larr = draft.linkDataArray;
        larr = larr.filter((ld: go.ObjectData) => {
          if (!fromKey && ld[path] === value) {
            // 起点为空
            console.log(path, value, '❌调试-删除节点所有连线,起点-', value);
            return false;
          }
          if (fromKey && ld.from === fromKey && ld[path] === value) {
            // 起点有值
            console.log(path, value, '❌调试-即将删除连线,起点-', fromKey);
            return false;
          }

          return true;
        });
        draft.linkDataArray = larr;
        this.refreshLinkIndex(larr);
        draft.skipsDiagramUpdate = false;
      })
    );
  }

  /**
   * 处理右侧检查器的修改事件, 当失去焦点时, 更新图表的数据模型
   * @param path 被修改的属性名路径
   * @param value 新的value值
   * @param isBlur 失去焦点事件, 表示编辑结束
   */
  public handleInputChange(path: string, value: any, isBlur: boolean) {
    console.log('检查器被修改了!!!====!!!', path, value, isBlur);
    this.setState(
      produce((draft: IState) => {
        const data = draft.selectedData as go.ObjectData; // only reached if selectedData isn't null
        // console.log('handleInputChange -> data' + JSON.stringify(draft));
        data[path] = value;
        if (isBlur) {
          // 只有失去焦点才会去更新数据
          const key = data.key;
          console.log(key, '组件配置被修改>>>>>>>>>>>>>>>流程图修改update>>>>>>>>>>>>>>>');
          if (key < 0) {
            // negative keys are links
            // key为负值时, 是链接
            const idx = this.mapLinkKeyIdx.get(key);
            if (idx !== undefined && idx >= 0) {
              draft.linkDataArray[idx] = data;
              draft.skipsDiagramUpdate = false;
            }
          } else {
            // 节点
            const idx = this.mapNodeKeyIdx.get(key);
            console.log(JSON.stringify(data));
            if (idx !== undefined && idx >= 0) {
              draft.nodeDataArray[idx] = data;
              draft.skipsDiagramUpdate = false;
            }
          }
        }
      })
    );
  }
  /**
   * 处理组件高亮status
   * @param data 被修改的节点
   * @param path 被修改的属性名路径
   * @param value 新的value值
   */
  public handleStatusChange(data: go.ObjectData, path: string, value: any) {
    console.log('status修改!!', data, path, value);
    this.setState(
      produce((draft: IState) => {
        data[path] = value;

        // 只有失去焦点才会去更新数据
        const key = data.key;
        // console.log("handleInputChange -> key", key);

        const idx = this.mapNodeKeyIdx.get(key);
        if (idx !== undefined && idx >= 0) {
          draft.nodeDataArray[idx] = data;
          draft.skipsDiagramUpdate = false;
        }
      })
    );
  }

  /**
   * 处理节点修改
   * @param data 被修改的节点
   * @param value 新的value值
   */
  public handleNodeChange(data: go.ObjectData, value: any) {
    console.log('handleNodeChange******node修改!!', data, value);
    this.setState(
      produce((draft: IState) => {
        data = value;
        const key = data.key;
        const idx = this.mapNodeKeyIdx.get(key);
        if (idx !== undefined && idx >= 0) {
          draft.nodeDataArray[idx] = data;
          draft.skipsDiagramUpdate = false;
        }
      })
    );
  }

  /**
   * Handle changes to the checkbox on whether to allow relinking.
   * @param e a change event from the checkbox
   */
  public handleRelinkChange(e: any) {
    const target = e.target;
    const value = target.checked;
    this.setState({
      modelData: { canRelink: value },
      skipsDiagramUpdate: false,
    });
  }
  // 修改全屏操作返回方法
  fixFullmothed = (diavalue: any) => {
    //console.log(diavalue);
    // if (this.state.isFullbollen_left == 18) {
    //   this.setState({
    //     isFullbollen_left: 24
    //   })
    // } else if (this.state.isFullbollen_left == 24) {
    //   this.setState({
    //     isFullbollen_left: 18
    //   })
    // }
  };

  /**
   * 流程图展示
   * @param versionId 版本ID
   * @param currentFlowStr 流程数据（字符串形式存储在数据库）
   */
  showModelData = (versionId: number, currentFlowStr: string) => {
    let currentObj: any;
    if (currentFlowStr && currentFlowStr !== '') {
      // 流程数据-非空
      currentObj = JSON.parse(currentFlowStr);
    } else {
      // 流程数据-空
      // eslint-disable-next-line prefer-const
      let { isView, nodeDataArray, linkDataArray } = this.state;
      if (!isView) {
        // 在编辑模式下，缺少【开始组件】需要前端添加
        nodeDataArray = [
          {
            key: 0,
            category: 'StartComponent',
            title: '开始组件',
            name: '开始',
            loc: '90 -370',
          },
        ];
      }
      currentObj = {
        nodeDataArray,
        linkDataArray,
      };
    }
    const { nodeDataArray, linkDataArray } = currentObj;
    this.setState(
      {
        diagramId: versionId,
        nodeDataArray,
        linkDataArray,
      },
      () => {
        this.initFlowMaps(nodeDataArray, linkDataArray);
      }
    );
  };
  /**
   * 从接口取流程图数据，画流程图
   * @param type 状态'publish'-已发布，'draft'-草稿
   * @callBack 回调函数
   */
  createFlowModel = async (type: 'publish' | 'draft', callBack?: Function) => {
    this.setState({
      loading: true,
    });
    try {
      const { versionId } = this.props;
      if (!versionId) return;
      const { code, data, tips } = await getFlow(versionId, {
        type,
      });

      if (code === 30021) {
        // 其他人正在编辑中，禁止切换【草稿】操作
        message.error(`${tips}(错误码: ${code})`);
        this.setState({
          loading: false,
        });
        return;
      }
      // 请求成功>>>流程对应的Json字符串
      const { content } = data;
      // 处理特殊情况
      callBack && callBack({ versionId, content });
      this.showModelData(versionId, content);
    } catch (error) {
      console.error(`系统异常: ${JSON.stringify(error)}`);
    }
    this.setState({
      loading: false,
    });
  };

  showDrawer = () => {
    this.setState({
      visible: true,
    });
  };
  onClose = () => {
    console.log('【组件】配置弹窗-关闭');
    this.setState({
      visible: false,
    });
  };

  /**切换流程标签，清空流程数据
   * isView:true-预览，false-可编辑
   */
  resetFlow = (isView: boolean) => {
    this.setState(
      {
        isView,
        diagramId: 0,
        nodeDataArray: [],
        linkDataArray: [],
        modelData: {
          canRelink: false,
        },
        selectedData: null,
        skipsDiagramUpdate: false,
      },
      () => {
        this.initFlowMaps([], []);
      }
    );
  };
  /**
   * 切换流程视图
   */
  changeFlowView = (type: 'publish' | 'draft') => {
    this.createFlowModel(type, () => {
      const isView = type === 'publish' ? true : false;
      this.resetFlow(isView);
    });
  };

  /**
   * 同步已发布版本到草稿状态
   */
  syncPublishToDraftFlow = () => {
    this.createFlowModel('publish', async ({ versionId, content }: any) => {
      const key = 'syncKey';
      message.loading({ content: '正在同步', key });
      this.resetFlow(false);

      // 保存【草稿】到数据库
      await postFlow({
        versionId,
        content,
        isPublish: false,
      });
      message.success({ content: '同步完成', key, duration: 1 });
    });
  };

  /**标签卡切换 */
  private handleViewChange = (e: RadioChangeEvent) => {
    const isView = e.target.value;
    const type = isView ? 'publish' : 'draft';
    this.changeFlowView(type);
  };

  public render() {
    const { selectedData, diagramId, isView, loading } = this.state;
    return (
      <div className="flow-manage-wrap" ref={this.container}>
        <div className="palette-wrap">
          {/* 顶部左侧-调色板-选择区 */}
          {/* 草稿状态：isView为false时，才显示顶部配置项 */}
          {!isView && (
            <PaletteWrapper
              nodeDataArray={this.state.paletteNodeDataArray}
              modelData={this.state.modelData}
            />
          )}
          {/* 顶部右侧-版本切换-按钮区 */}
          <Radio.Group className="change-view-box" value={isView} onChange={this.handleViewChange}>
            <Radio.Button value={true}>已发布</Radio.Button>
            <Radio.Button value={false}>草稿</Radio.Button>
          </Radio.Group>
        </div>
        <Spin spinning={loading}>
          <Row gutter={16} className="diagram—wrap">
            {diagramId > 0 && (
              <Col span={this.state.isFullbollen_left}>
                {/* 底部左侧-流程图-展示区 */}
                {isView ? (
                  <DiagramWrapperView
                    key={'publish' + diagramId}
                    nodeDataArray={this.state.nodeDataArray}
                    linkDataArray={this.state.linkDataArray}
                    modelData={this.state.modelData}
                    skipsDiagramUpdate={this.state.skipsDiagramUpdate}
                    onDiagramEvent={this.handleDiagramEvent}
                    onModelChange={this.handleModelChange}
                    onStatusChange={this.handleStatusChange}
                    onNodeChange={this.handleNodeChange}
                    onDiagramDbEvent={this.dbhandleDiagramEvent}
                    ononeDiagramDbEvent={this.onehandleDiagramEvent}
                    versionId={diagramId}
                    fixedSpan={(diavalue: any) => {
                      this.fixFullmothed(diavalue);
                    }}
                  />
                ) : (
                  <DiagramWrapper
                    key={'draft' + diagramId}
                    nodeDataArray={this.state.nodeDataArray}
                    linkDataArray={this.state.linkDataArray}
                    modelData={this.state.modelData}
                    skipsDiagramUpdate={this.state.skipsDiagramUpdate}
                    onDiagramEvent={this.handleDiagramEvent}
                    onModelChange={this.handleModelChange}
                    onStatusChange={this.handleStatusChange}
                    onNodeChange={this.handleNodeChange}
                    onDiagramDbEvent={this.dbhandleDiagramEvent}
                    ononeDiagramDbEvent={this.onehandleDiagramEvent}
                    versionId={diagramId}
                    fixedSpan={(diavalue: any) => {
                      this.fixFullmothed(diavalue);
                    }}
                    onSyncPublishToDraftFlow={this.syncPublishToDraftFlow}
                    onChangeFlowView={this.changeFlowView}
                  />
                )}
              </Col>
            )}
          </Row>
        </Spin>
        <Drawer
          title={null}
          placement="right"
          closable={false}
          onClose={this.onClose}
          mask={false}
          width={360}
          getContainer={() => {
            return this.container.current;
          }}
          visible={this.state.visible}
        >
          <InspectorContext.Provider
            value={{
              versionId: this.props.versionId,
              isView: isView,
              category: selectedData && selectedData.category,
              selectedData,
              nodeDataArray: this.state.nodeDataArray,
              onInputChange: this.handleInputChange, // 弹窗内容发生改变
              onRemoveLink: this.handleRemoveLink,
              onModifyLink: this.handleModifyLink,
            }}
          >
            {selectedData?.category && <SelectionInspector />}{' '}
          </InspectorContext.Provider>
        </Drawer>
      </div>
    );
  }
}

export default FlowManage;
